class_name Helpers


const MONTHS: PoolStringArray = PoolStringArray(["January", "February",
		"March", "April", "May", "June", "July", "August", "September",
		"October", "November", "December"])


static func array_all(arr: Array) -> bool:
	"""
	Returns:
		`true` if `bool(x) == true` for all x in `arr`, `false` otherwise.
		If `arr` is empty returns `true`
	"""
	var all: bool = true
	for item in arr:
		if bool(item) == false:
			all = false
			break
	return all


static func array_any(arr: Array) -> bool:
	"""
	Returns:
		`true` if `bool(x) == true` for any x in `arr`, `false` otherwise.
		If `arr` is empty returns `false`
	"""
	var any: bool = false
	for item in arr:
		if bool(item) == true:
			any = true
			break
	return any


static func array_remove_duplicates(arr: Array) -> Array:
	var new_arr: Array = []
	for item in arr:
		if not (item in new_arr):
			new_arr.append(item)
	return new_arr


static func dictionary_merge_into(dict1: Dictionary, dict2: Dictionary,
		deep: bool=false, merge_duplicates: bool=true) -> void:
	"""
	Merges `dict2` into `dict1`
	
	The result is the union of `dict1` and `dict2`. Where a key is in both
	`dict1` and `dict2` the value of `dict2` is used
	
	Args:
		dict1: First dictionary. The result of the merge will be stored here
		dict2: Second dictionary. Will be unchanged
		deep: If true, inner dictionaries and arrays will be merged
		merge_duplicates: Only applies if `deep` is true. If false will not
			merge duplicates from inner arrays in `dict2` into inner arrays in
			`dict1`. If there are already duplicates in inner arrays in `dict1`
			they will remain
	"""
	for key in dict2:
		if deep and dict1.has(key):
			# Merge arrays
			if dict1[key] is Array and dict2[key] is Array:
				if merge_duplicates:
					dict1[key] += dict2[key]
				else:
					for item in dict2[key]:
						if not (item in dict1[key]):
							dict1[key].append(item)
			# Merge dictionaries
			elif dict1[key] is Dictionary and dict2[key] is Dictionary:
				dictionary_merge_into(dict1[key], dict2[key], deep,
						merge_duplicates)
			# The values aren't both arrays and aren't both dictionaries so set
			# to `dict2`s value
			else:
				dict1[key] = dict2[key]
		else:
			dict1[key] = dict2[key]


static func datetime_difference(past_unix_time: int, future_unix_time: int
		) -> Dictionary:
	"""
	Args:
		past_unix_time: A unix timestamp less than or equal to
			`future_unix_time`
		future_unix_time: A unix timestamp more than or equal to
			`past_unix_time`
	
	Returns:
		How many days, hours, minutes, etc, `past_unix_time` occured before
		`future_unix_time` and the key "error" == `false` if no error occurred.
		If an error occurred then returns the key-value pair "error" == `true`
	"""
	if past_unix_time > future_unix_time:
		var msg: String = "`past_unix_time` must be less than or equal to"
		msg += " `future_unix_time`"
		push_error(msg)
		return {"error": true}
	
	var date: Dictionary = \
			OS.get_datetime_from_unix_time(future_unix_time - past_unix_time)
	var date_diff: Dictionary = {
		"day": date["day"] - 1,
		"month": date["month"] - 1,
		"year": date["year"] - 1970,
		"hour": date["hour"],
		"minute": date["minute"],
		"second": date["second"],
		"error": false,
	}
	return date_diff

static func parse_timestamp_to_relative_string(timestamp: int) -> String:
	"""
	Converts the given unix timestamp to a string saying how long ago it was.
	If unable to convert the timestamp returns an empty string
	
	Args:
		timestamp: A unix timestamp. Must be less than or equal to the current
			time
	"""
	var timestamp_text: String = ""
	var posted_date_difference: Dictionary = \
			datetime_difference(timestamp, OS.get_unix_time())
	if posted_date_difference["error"] == false:
		var time_word: String = ""
		var plural: bool = false
		# Use the word corresponding to the largest period of time with a value
		# greater than 0
		for word in ["year", "month", "day", "hour", "minute", "second"]:
			if posted_date_difference[word] > 0:
				time_word = word
				if posted_date_difference[word] > 1:
					plural = true
				break
		
		if time_word != "":
			timestamp_text = "%d %s ago" % [
					posted_date_difference[time_word],
					time_word if not plural else time_word + "s"]
		else:
			# `time_word` will only be empty if the timestamp is the current
			# time
			timestamp_text = "Just now"
	return timestamp_text


static func month_to_string(int_month: int) -> String:
	""" Converts the month from numerical form (1 to 12) into string form """
	if int_month < 1 or int_month > 12:
		return ""
	
	return MONTHS[int_month - 1]
